import pyglet

import cocos
from cocos.director import director
from cocos.menu import *

from gamelib.options import options
from gamelib import character, music, ui, menustyle

class InventoryLayer(ui.Root):
    def __init__(self, party, character=None):
        super(InventoryLayer, self).__init__(style=options.style)
        self.party = party
        if character is None:
            character = party.characters[0]
        self.character = character

        # make the background a little nicer
        self.background = ui.RepeatedTileRect('canvas-bg.png',
            self._x, self._y, self._width, self._height, self.batch)

        self.style.text['font_size'] = 16
        self.style.text_bold['font_size'] = 18
        '''
        self.style.text['font_name'] = 'A Font with Serifs'
        self.style.text_bold['font_name'] = 'CurlyHogRunes-Bold'
        #self.style.text['font_name'] = 'A Font with Serifs. Disordered'
        '''

    def on_enter(self):
        super(InventoryLayer, self).on_enter()

        w, h = director.get_window_size()

        row = ui.Row(self)

        # three columns
        style = row.style.copy()
        style.background.fill_color = (240, 240, 240, 255)
        ui.Column(row, width=w//3, id='character', on_drop=self.drop_body, style=style)
        mid = ui.Column(row, width=w//3)
        if self.parent.party_mode:
            ui.Column(row, width=w//3, id='party', on_drop=self.drop_party, style=style)

        # mid column
        ui.Label(mid, text='Pack', bold=True)
        ui.Column(mid, height=h//2, id='pack', on_drop=self.drop_pack)
        chars = ui.Column(mid, height=h-mid.content_height)

        self.set_character()
        if self.parent.party_mode:
            self.set_party()

        # add character buttons
        ui.Label(chars, text='Select Character:', bold=True)
        self.character_names = []
        for character in self.party.characters:
            ui.Label(chars, text=character.name,
                on_click=lambda w, x, y, b, m, c=character: self.activate_character(c))

        ui.Spacer(chars, height=16)

        ui.Label(chars, text='Hints:', bold=True)
        text = [
            "Click on a character's name above to select.",
            'Drag and drop items to move them around.',
            'Press <esc> when you are finished.',
        ]
        if self.parent.party_mode:
            text.insert(-1, "Click on a character's skill to add experience.")
        ui.Label(chars, multiline=True, text='\n'.join(text))

        self.music_player = music.play('music_town_mp.ogg')

    def drop_body(self, widget, dropped):
        if dropped.parent_widget.id == 'character': return
        if dropped.parent_widget.id == 'pack':
            item = self.remove_from_pack(dropped.id)
        elif dropped.parent_widget.id == 'party':
            item = self.remove_from_party(dropped._item)
        self.add_to_body(item)

    def drop_pack(self, widget, dropped):
        if dropped.parent_widget.id == 'pack': return
        if dropped.parent_widget.id == 'character':
            item = self.remove_from_body(dropped._item, dropped._slot)
        elif dropped.parent_widget.id == 'party':
            item = self.remove_from_party(dropped._item)
        self.add_to_pack(item)

    def drop_party(self, widget, dropped):
        if dropped.parent_widget.id == 'party': return
        if dropped.parent_widget.id == 'pack':
            item = self.remove_from_pack(dropped.id)
        elif dropped.parent_widget.id == 'character':
            item = self.remove_from_body(dropped._item, dropped._slot)
        self.add_to_party(item)

    def set_character(self):
        w, h = director.get_window_size()

        b = self.character.body

        char = self.by_id['character']

        ui.Text(char, self.character.name, bold=True)

        for slot, slabel in zip(b.slots, b.slot_labels):
            item = b.get(slot)
            if item is None:
                label = ''
                on_drag = None
            else:
                label = item.label
                on_drag = ui.generic_drag_text(label)
            label = slabel + ': ' + label
            t = ui.Text(char, label, id='body-%s'%slot, on_drag=on_drag)
            t._item = item
            t._slot = slot

        # ATTRIBUTES
        ui.Text(char, 'Character Attributes:', bold=True)
        ui.Text(char, 'STR: %s  DEX: %s  CON: %s'%(self.character.strength,
            self.character.dexterity, self.character.constitution))
        ui.Text(char, 'INT: %s  WIS: %s  CHR: %s'%(self.character.intelligence,
            self.character.wisdom, self.character.charisma))

        # EXPERIENCE
        ui.Text(char, 'Experience:', bold=True)
        ui.Text(char, str(self.character.experience), id='experience')

        # SKILLS
        ui.Text(char, 'Character Skills:', bold=True)
        for skill, value in self.character.skills.items():
            label = character.skill_descriptions[skill]['label']
            t = ui.Text(char, '%s: %s'%(label, value), id='skill-%s'%skill)
            if self.parent.party_mode:
                t.on_click = lambda w,x,y,b,m, skill=skill:self.xp_to_skill(skill)
        if self.parent.party_mode:
            if self.character.experience >= 5:
                ui.Text(char, 'Buy New Skill (5 XP required)',
                    on_click=self.buy_new_skill)
            else:
                ui.Text(char, 'Buy New Skill (5 XP required)')

        '''
        # ABILITIES
        ui.Text(char, text='Character Abilities:', bold=True)
        if self.parent.party_mode:
            if self.character.experience >= 5:
                ui.Text(char, 'Buy New Ability (5 XP required)',
                    on_click=self.buy_new_ability)
            else:
                ui.Text(char, 'Buy New Ability (5 XP required)')
        '''

        # pack contents
        pack = self.by_id['pack']
        for item in self.character.carried:
            label = item.label
            print (item, label)
            t = ui.Text(pack, label, on_drag=ui.generic_drag_text(label))
            t._item = item

    party_items = None
    def set_party(self):
        w, h = director.get_window_size()

        items = self.party.items

        party = self.by_id['party']

        ui.Label(party, text='Party Items', bold=True)
        ui.Label(party, text='%d coins'%self.party.coins)

        # sort the items and get counts of duplicates
        items.sort()
        last = (None, None)
        l = []
        for item in items:
            if item == last[0]:
                last[1] += 1
            else:
                last = [item, 1]
                l.append(last)

        for item, count in l:
            t = ui.Label(party, text='%d x %s'%(count, item.label),
                on_drag=ui.generic_drag_text(item.label))
            t._item = item
            t._count = count


    def xp_to_skill(self, skill):
        if not self.character.experience: return
        if self.character.skills[skill] == 10: return
        self.character.experience -= 1
        self.by_id['experience'].text = str(self.character.experience)
        self.character.skills[skill] += 1
        label = character.skill_descriptions[skill]['label']
        self.by_id['skill-%s'%skill].text = '%s: %s'%(label,
            self.character.skills[skill])

    def buy_new_skill(self, *args):
        director.push(cocos.scene.Scene(BuySkillMenu('Buy Skill', self.character)))

    def activate_character(self, character):
        self.character = character
        self.by_id['character'].clear()
        self.by_id['pack'].clear()
        self.set_character()

    def add_to_body(self, item):
        id = 'body-%s'%item.slot
        label = self.by_id[id]
        body = self.character.body

        # move an existing item in that slot to the pack
        if label._item:
            body.equip(None, item.slot)
            self.add_to_pack(label._item)

        # update dest label
        label._item = item
        slabel = self.character.body.slot_dict[item.slot]
        label.text = '%s: %s'%(slabel, item.label)
        label.on_drag = ui.generic_drag_text(item.label)
        body.equip(item)

    def remove_from_body(self, item, slot):
        '''Remove something from the body slot determined by the ui.Element
        it's represented by.
        '''
        body = self.character.body

        # remove from body
        body.equip(None, slot)

        # update source label
        slabel = body.slot_dict[slot]

        id = 'body-%s'%item.slot
        label = self.by_id[id]
        label.text = slabel + ':'
        label._item = None
        label.on_drag = None

        return item

    def add_to_pack(self, item):
        if len(self.character.carried) > 10: # XXX ARBITRARY NUMBER ALERT
            return self.add_to_party(item)
        pack = self.by_id['pack']
        t = ui.Label(pack, text=item.label,
            on_drag=ui.generic_drag_text(item.label))
        t._item = item
        self.character.carried.append(item)

    def remove_from_pack(self, id):
        '''Note that this will remove the first equivalent item from the pack and
        not necessarily the exact same item. The actual item removed is returned.
        '''
        label = self.by_id[id]
        label.delete()
        item = label._item
        self.character.carried.remove(item)
        return item

    def add_to_party(self, item):
        party = self.by_id['party']
        for label in party:
            if item == getattr(label, '_item', None):
                # found existing item
                label._count += 1
                label.text = '%d x %s'%(label._count, item.label)
                return

        # add new item
        t = ui.Label(party, text='1 x %s'%item.label,
            on_drag=ui.generic_drag_text(item.label))
        t._item = item
        t._count = 1

        self.party.items.append(item)

    def remove_from_party(self, item):
        party = self.by_id['party']
        for label in party:
            if getattr(label, '_item', None) == item:
                label._count -= 1
                if label._count > 0:
                    label.text = '%d x %s'%(label._count, item.label)
                else:
                    label.delete()
                # might not be precisely the same object
                item = label._item
                break
        self.party.items.remove(item)
        return item

    def on_exit(self):
        self.music_player.pause()
        self.music_player = None
        super(InventoryLayer, self).on_exit()


class InventoryScreen(cocos.scene.Scene):
    def __init__(self, party, character=None):
        super(InventoryScreen, self).__init__()
        self.party = party
        self.character = character

    def on_enter(self):
        super(InventoryScreen, self).on_enter()
        self.l = InventoryLayer(self.party, self.character)
        self.add(self.l)

    def on_exit(self):
        super(InventoryScreen, self).on_exit()
        self.remove(self.l)

class PartyInventoryScreen(InventoryScreen):
    party_mode = True

class CharacterInventoryScreen(InventoryScreen):
    party_mode = False



class BuySkillMenu(menustyle.MyStyleMenu):
    def __init__(self, title, character):
        super(BuySkillMenu, self).__init__(title)
        self.character = character

    def on_enter(self):
        super(BuySkillMenu, self).on_enter()
        self.font_item['font_size'] = 32
        self.font_item_selected['font_size'] = 32

        # ugh, menu should DO this
        for child in self.get_children():
            self.remove(child)

        options = []
        for skill, info in character.skill_descriptions.items():
            if skill in self.character.skills: continue
            options.append(MenuItem(info['label'], lambda skill=skill: self.add_skill(skill)))
        options.append(MenuItem('Cancel', self.on_quit))

        self.create_menu(options)

    def on_quit(self):
        director.pop()

    def add_skill(self, skill_name):
        self.character.skills[skill_name] = 1
        self.character.experience -= 5
        director.pop()

